#include "RedisManager.h"
#include <string.h>
#include "stdlib.h"

CRedisManager::CRedisManager(void) :
		m_redisConnect(NULL),
		m_redisReply(NULL),
		m_strIp("127.0.0.1"),
		m_iPort(6379),
		m_iSecond(10),
		m_iExpireTime(10 * 60 * 60 * 24)
{
}

CRedisManager::~CRedisManager(void)
{
	if (m_redisConnect != NULL)
	{
		redisFree(m_redisConnect);
		m_redisConnect = NULL;
	}
	if (m_redisReply != NULL)
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}
}

bool CRedisManager::Connect()
{
	struct timeval tv;
	bool bResult = true;

	tv.tv_sec = m_iSecond;
	tv.tv_usec = m_iSecond * 1000;
	m_redisConnect = redisConnect(m_strIp.c_str(), m_iPort);
	if (m_redisConnect->err)
	{
		//std::cout << "Redis Connect Error: " << m_redisConnect->errstr << std::endl;
		bResult = false;
	}

	return bResult;
}

void CRedisManager::Close()
{
	if(m_redisConnect != NULL)
	{
		redisFree(m_redisConnect);
		m_redisConnect = NULL;
	}

}

void CRedisManager::Set(const std::string &strKey, const std::string &strValue)
{
	m_redisReply = (redisReply*) redisCommand(m_redisConnect, "SET %s %s",
			strKey.c_str(), strValue.c_str());
	if (m_redisReply != NULL)
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}else
	{
		Close();
	}
}

std::string CRedisManager::Get(const std::string &strKey)
{
	std::string strData = "";
	m_redisReply = (redisReply*) redisCommand(m_redisConnect, "GET %s",
			strKey.c_str());

	if (m_redisReply != NULL)
	{
		strData = m_redisReply->str;

		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}else
	{
		Close();
	}

	return strData;
}

void CRedisManager::SetHashKeyValue(const std::string &strTableName,
		std::map<std::string, std::string> &mapKeyValueLists)
{
	if (mapKeyValueLists.size() <= 0)
	{
		return;
	}
	std::string strCommand;
	strCommand = "HMSET ";
	strCommand += strTableName;

	std::map<std::string, std::string>::iterator it;
	for (it = mapKeyValueLists.begin(); it != mapKeyValueLists.end(); it++)
	{
		strCommand += " " + it->first + " " + it->second;
	}

	m_redisReply = (redisReply*) redisCommand(m_redisConnect,
			strCommand.c_str());
	if (m_redisReply == NULL)
	{
		//std::cout << "Redis connect Fail." << std::endl;
		Close();
	} else if (!(m_redisReply->type == REDIS_REPLY_STATUS/* && strcmp(m_redisReply->str,"OK")==0*/))
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
		//std::cout << "Redis Fail Exe Commond." << std::endl;
	} else if (m_redisReply != NULL)
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}
}

void CRedisManager::SetHashKeyValueOrder(const std::string &strTableName,
		std::list<std::string> &strKeyLists,
		std::list<std::string> &strValueLists)
{
	if (strKeyLists.size() <= 0 || strValueLists.size() <= 0)
	{
		return;
	}
	std::string strCommand;
	strCommand = "HMSET ";
	strCommand += strTableName;

	std::list<std::string>::iterator itKey = strKeyLists.begin();
	std::list<std::string>::iterator itValue = strValueLists.begin();

	for (; itKey != strKeyLists.end(), itValue != strValueLists.end();
			itKey++, itValue++)
	{
		strCommand += " " + *itKey + " " + *itValue;
	}

	m_redisReply = (redisReply*) redisCommand(m_redisConnect,
			strCommand.c_str());
	if (m_redisReply == NULL)
	{
		//std::cout << "Redis connect Fail." << std::endl;
		Close();
	} else if (!(m_redisReply->type == REDIS_REPLY_STATUS/* && strcmp(m_redisReply->str,"OK")==0*/))
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
		//std::cout << "Redis Fail Exe Commond." << std::endl;
	} else if (m_redisReply != NULL)
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}
}

void CRedisManager::SetHashKeyValueBinary(const std::string & strTableName, std::vector<std::string> & vstrKeys,std::vector<void *>& vpValues, std::vector<int> & vpValuesLen)
{
	if (vstrKeys.size() <= 0 || vpValues.size() <= 0 || vpValuesLen.size() <= 0)
	{
		return;
	}

	std::vector<const char *> argv(vstrKeys.size() + vpValues.size() + 2);
	std::vector<size_t> argvLen(vstrKeys.size() + vpValues.size() + 2);

	int iIndex = 0;

	char pHmsetCmd[] = "HMSET";

	argv[iIndex] = pHmsetCmd;
	argvLen[iIndex] = sizeof(pHmsetCmd)  - 1;
	iIndex ++;

	argvLen[iIndex] = strTableName.size();
	argv[iIndex] = strTableName.data();
	iIndex ++;

	for(size_t i = 0; i < vstrKeys.size(); i ++)
	{
		argvLen[iIndex] = vstrKeys.at(i).size();
		argv[iIndex] = vstrKeys.at(i).data();
		iIndex ++;

		argvLen[iIndex] = vpValuesLen[i];
		argv[iIndex] = new char[vpValuesLen[i]];
		memset((void *)argv[iIndex], 0x0, vpValuesLen[i]);
		memcpy((void *)argv[iIndex], vpValues[i], vpValuesLen[i]);
		iIndex ++;
	}

	m_redisReply = (redisReply *)redisCommandArgv(m_redisConnect,
			argv.size(), &argv[0], &argvLen[0]);
	if (m_redisReply == NULL)
	{
		//std::cout << "Redis connect Fail." << std::endl;
		Close();
	} else if (!(m_redisReply->type == REDIS_REPLY_STATUS/* && strcmp(m_redisReply->str,"OK")==0*/))
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
		//std::cout << "Redis Fail Exe Commond." << std::endl;
	} else if (m_redisReply != NULL)
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}

	//delete
	for(size_t i = 3; i <argv.size(); i += 2)
	{
		delete  argv.at(i);
		argv.at(i) = NULL;
	}
}

void CRedisManager::GetHashAllDataBinary(std::vector<std::string> &vstrKeys, std::vector<void *> &vpValues, const std::string & strTableName)
{
	if(strTableName.empty())
		return ;

	char pHgetallCmd[] = "HGETALL";
	std::vector<const char *> argv(2);
	std::vector<size_t> argvLen(2);

	argv[0] = pHgetallCmd;
	argvLen[0] = sizeof(pHgetallCmd) - 1;

	argv[1] = strTableName.data();
	argvLen[1] = strTableName.size();

	m_redisReply = (redisReply *)redisCommandArgv(m_redisConnect,
			argv.size(), &argv[0], &argvLen[0]);
	if (m_redisReply == NULL)
	{
		//std::cout << "Redis connect Fail." << std::endl;
		Close();
	} else if (m_redisReply->type != REDIS_REPLY_ARRAY)
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
		//std::cout << "Redis Fail Exe Commond." << std::endl;
	} else if (m_redisReply != NULL)
	{
		//处理hgetall获取的数据
		for(size_t i = 0; i < m_redisReply->elements; )
		{
			vstrKeys.push_back(m_redisReply->element[i]->str);
			i ++;

			void *pData = NULL;

			pData = malloc(m_redisReply->element[i]->len);
			memset(pData, 0x0, m_redisReply->element[i]->len);
			memcpy(pData, m_redisReply->element[i]->str, m_redisReply->element[i]->len);

			vpValues.push_back(pData);
			i ++;
		}

		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}
}

void CRedisManager::SetKeyExpireTime(const std::string & strKey)
{
	std::string strCommand = "";

	strCommand = "EXPIRE " + strKey + " ";
	strCommand += Value2String<int>(m_iExpireTime);

	m_redisReply = (redisReply*) redisCommand(m_redisConnect,
			strCommand.c_str());
	if (m_redisReply == NULL)
	{
		//std::cout << "Redis connect Fail." << std::endl;
		Close();
	} else if (!(m_redisReply->type == REDIS_REPLY_STATUS/* && strcmp(m_redisReply->str,"OK")==0*/))
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
		//std::cout << "Redis Fail Exe Commond." << std::endl;
	} else if (m_redisReply != NULL)
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}
}

bool CRedisManager::IsExistsKey(const std::string & strKey)
{
	bool bRet = false;
	std::string strCmd = "";

	strCmd = "EXISTS " + strKey;

	m_redisReply = (redisReply*) redisCommand(m_redisConnect,
			strCmd.c_str());
	if (m_redisReply == NULL)
	{
		Close();
	} else if (m_redisReply->type == REDIS_REPLY_INTEGER)
	{
		if(1 == m_redisReply->integer)
			bRet = true;

		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}

	return bRet;
}

bool CRedisManager::Ping()
{
	bool bRet = true;
	m_redisReply = (redisReply*) redisCommand(m_redisConnect, "ping");
	if (m_redisReply != NULL)
	{
		freeReplyObject(m_redisReply);
		m_redisReply = NULL;
	}else
	{
		bRet = false;
		Close();
	}

	return bRet;
}
